package com.fm.structure.list;

import com.fm.base.annotation.UnThreadSafe;

/**
 * @param <E> element type
 * @author finalmachine
 */
@UnThreadSafe
public class DoubleLinkedRing<E> {
    private DoubleLinkedNode<E> curr = null;
    private int size = 0;

    private void removeNode(DoubleLinkedNode<E> node) {
        if (node.getPrev() == node) {
            curr = null;
        } else {
            node.getPrev().setNext(node.getNext());
            node.getNext().setPrev(node.getPrev());
            if (curr == node) {
                curr = curr.getNext();
            }
        }
        size--;
    }

    public void add(E element) {
        if (curr == null) {
            curr = new DoubleLinkedNode<>(element, null, null);
            curr.setPrev(curr);
            curr.setNext(curr);
        } else {
            DoubleLinkedNode<E> temp = new DoubleLinkedNode<>(element, curr.getPrev(), curr);
            curr.getPrev().setNext(temp);
            curr.setPrev(temp);
        }
        size++;
    }

    public E getElement() {
        if (curr == null) {
            return null;
        } else {
            try {
                return curr.getValue();
            } finally {
                curr = curr.getNext();
            }
        }
    }

    public boolean removeFromPrev(E element) {
        DoubleLinkedNode<E> p = curr;
        if (p.getValue().equals(element)) {
            removeNode(p);
            return true;
        }
        p = curr.getPrev();
        int count = 0;
        while (p != curr && count++ < size) {
            if (p.getValue().equals(element)) {
                removeNode(p);
                return true;
            }
            p = p.getPrev();
        }
        return false;
    }

    public boolean removeFromNext(E element) {
        DoubleLinkedNode<E> p = curr;
        if (p.getValue().equals(element)) {
            removeNode(p);
            return true;
        }
        p = curr.getNext();
        int count = 0;
        while (p != curr && count++ < size) {
            if (p.getValue().equals(element)) {
                removeNode(p);
                return true;
            }
            p = p.getNext();
        }
        return false;
    }

    public int size() {
        return size;
    }
}
